package com.czh.subject.domain.service.impl;

import com.alibaba.fastjson2.JSON;
import com.czh.subject.common.enums.SubjectIsDeleteEnum;
import com.czh.subject.domain.convert.SubjectCategoryConverter;
import com.czh.subject.domain.convert.SubjectLabelConverter;
import com.czh.subject.domain.entity.SubjectCategoryBO;
import com.czh.subject.domain.entity.SubjectLabelBO;
import com.czh.subject.domain.service.SubjectCategoryDomainService;
import com.czh.subject.domain.utils.CacheUtil;
import com.czh.subject.infra.basic.entity.SubjectCategory;
import com.czh.subject.infra.basic.entity.SubjectLabel;
import com.czh.subject.infra.basic.entity.SubjectMapping;
import com.czh.subject.infra.basic.service.SubjectCategoryService;
import com.czh.subject.infra.basic.service.SubjectLabelService;
import com.czh.subject.infra.basic.service.SubjectMappingService;
import jakarta.annotation.Resource;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author czh01
 * @version 1.0
 * @description:
 * @date 2024/7/25 上午 1:15
 */
@Service
@Log4j2
public class SubjectCategoryDomainServiceImpl implements SubjectCategoryDomainService {

    @Resource
    private SubjectCategoryService subjectCategoryService;
    @Resource
    private SubjectMappingService subjectMappingService;
    @Resource
    private SubjectLabelService subjectLabelService;
    @Resource
    private ThreadPoolExecutor labelThreadPoolExecutor;
    @Resource
    private CacheUtil<SubjectCategoryBO> cacheUtil;



    @Override
    public Boolean addSubjectCategory(SubjectCategoryBO subjectCategoryBo) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convert(subjectCategoryBo);
        return subjectCategoryService.insert(subjectCategory) > 0;
    }

    @Override
    public List<SubjectCategoryBO> queryCategory(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convert(subjectCategoryBO);
        subjectCategory.setIsDeleted(SubjectIsDeleteEnum.NO_DELETED.getCode());
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
        List<SubjectCategoryBO> subjectCategoryBOList = SubjectCategoryConverter.INSTANCE.convert(subjectCategoryList);
        List<Map<String, Long>> categoryCountList = subjectCategoryService.queryCategoryCountByCondition();
        //j将标签数量插入categoryBO中
        subjectCategoryBOList.forEach(categoryBO -> {
            for (Map<String, Long> categoryCount : categoryCountList) {
                Long id = categoryCount.get("id");
                if (id != null && id.equals(categoryBO.getId())) {
                    categoryBO.setCount(categoryCount.get("count").intValue());
                    break;
                }
            }
        });
        return subjectCategoryBOList;
    }

    @Override
    public Boolean update(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convert(subjectCategoryBO);
        int update = subjectCategoryService.update(subjectCategory);
        return update > 0;
    }

    @Override
    public Boolean delete(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = SubjectCategoryConverter.INSTANCE.convert(subjectCategoryBO);
        return subjectCategoryService.delete(subjectCategory);
    }

    /**
     * 查询分类所对应标签
     *
     * @param category 分类
     * @return 分类id、标签Map
     */
    private Map<Long, List<SubjectLabelBO>> getLabelBOList(SubjectCategoryBO category) {
        if (log.isInfoEnabled()) {
            log.info("getLabelBOList:{}", JSON.toJSONString(category));
        }
        Map<Long, List<SubjectLabelBO>> labelMap = new HashMap<>();
        SubjectMapping subjectMapping = new SubjectMapping();
        subjectMapping.setCategoryId(category.getId());
        List<SubjectMapping> mappingList = subjectMappingService.querySubjectMappingList(subjectMapping);
        if (CollectionUtils.isEmpty(mappingList)) {
            return null;
        }
        List<Long> labelIdList = mappingList.stream().map(SubjectMapping::getLabelId).collect(Collectors.toList());
        List<SubjectLabel> subjectLabelList = subjectLabelService.batchQueryByCategoryId(labelIdList);
        labelMap.put(category.getId(), SubjectLabelConverter.INSTANCE.convert(subjectLabelList));
        return labelMap;
    }
    /**
     * 查询分类和标签
     */
    @Override
    @Deprecated
    public List<SubjectCategoryBO> queryCategoryAndLabel(SubjectCategoryBO subjectCategoryBO) {
        //查询分类BO
        SubjectCategory subjectCategory = new SubjectCategory();
        subjectCategory.setParentId(subjectCategoryBO.getId());
        subjectCategory.setIsDeleted(SubjectIsDeleteEnum.NO_DELETED.getCode());
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
        List<SubjectCategoryBO> subjectCategoryBOList = SubjectCategoryConverter.INSTANCE.convert(subjectCategoryList);
        if (CollectionUtils.isEmpty(subjectCategoryBOList)){
            return Collections.emptyList();
        }
        //给分类赋标签
        subjectCategoryBOList.forEach(category->{
            SubjectMapping subjectMapping = new SubjectMapping();
            subjectMapping.setSubjectId(category.getId());
            List<Long> labelIdList = subjectMappingService.querySubjectMappingList(subjectMapping).stream().map(SubjectMapping::getLabelId).toList();
            List<SubjectLabel> subjectLabelList = subjectLabelService.batchQueryByCategoryId(labelIdList);
            category.setSubjectLabelBOList(SubjectLabelConverter.INSTANCE.convert(subjectLabelList));
        });
        return subjectCategoryBOList;
    }
    /**
     * (优化1)查询分类和标签
     *多线程实现方式一
     * @since 2024/9/4 下午 11:01
     */
    @Override
    @Deprecated
    public List<SubjectCategoryBO> queryCategoryAndLabelOptimize1(SubjectCategoryBO subjectCategoryBO) {
        //查询分类BO
        SubjectCategory subjectCategory = new SubjectCategory();
        subjectCategory.setParentId(subjectCategoryBO.getId());
        subjectCategory.setIsDeleted(SubjectIsDeleteEnum.NO_DELETED.getCode());
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
        List<SubjectCategoryBO> subjectCategoryBOList = SubjectCategoryConverter.INSTANCE.convert(subjectCategoryList);
        if (CollectionUtils.isEmpty(subjectCategoryBOList)) {
            return Collections.emptyList();
        }
        List<FutureTask<Map<Long, List<SubjectLabelBO>>>> futureTaskList = new LinkedList<>();
        //线程池并发获取标签
        subjectCategoryBOList.forEach(category -> {
            FutureTask<Map<Long, List<SubjectLabelBO>>> futureTask = new FutureTask<>(() -> getLabelBOList(category));
            futureTaskList.add(futureTask);
            labelThreadPoolExecutor.submit(futureTask);
        });
        //将futureTaskList中的label对应赋值到category
        for (FutureTask<Map<Long, List<SubjectLabelBO>>> futureTask : futureTaskList) {
            try {
                Map<Long, List<SubjectLabelBO>> labelBOMap = futureTask.get();
                subjectCategoryBOList.forEach(category -> {
                    List<SubjectLabelBO> labelBOList = labelBOMap.get(category.getId());
                    category.setSubjectLabelBOList(labelBOList);
                });
            } catch (ExecutionException | InterruptedException e) {
                log.error("setSubjectLabelBOList error!");
            }
        }
        return subjectCategoryBOList;
    }

    /**
     * (优化2)查询分类和标签
     * 多线程实现方式2
     *  添加缓存
     * @since 2024/9/4 下午 11:01
     */
    @Override
    public List<SubjectCategoryBO> queryCategoryAndLabelOptimize2(SubjectCategoryBO subjectCategoryBO) {
        String cacheKey = "categoryAndLabelByPrentId."+subjectCategoryBO.getId();
        return cacheUtil.getCacheList(cacheKey, SubjectCategoryBO.class, (key) -> getSubjectCategoryBOList(subjectCategoryBO));
    }

    private List<SubjectCategoryBO> getSubjectCategoryBOList(SubjectCategoryBO subjectCategoryBO) {
        SubjectCategory subjectCategory = new SubjectCategory();
        subjectCategory.setParentId(subjectCategoryBO.getId());
        subjectCategory.setIsDeleted(SubjectIsDeleteEnum.NO_DELETED.getCode());
        List<SubjectCategory> subjectCategoryList = subjectCategoryService.queryCategory(subjectCategory);
        if (log.isInfoEnabled()) {
            log.info("SubjectCategoryController.queryCategoryAndLabel.subjectCategoryList:{}",
                    JSON.toJSONString(subjectCategoryList));
        }
        //多线程并发获取labelBO
        List<SubjectCategoryBO> categoryBOList = SubjectCategoryConverter.INSTANCE.convert(subjectCategoryList);
        List<CompletableFuture<Map<Long, List<SubjectLabelBO>>>> completableFutureList = categoryBOList.stream().map(category ->
                CompletableFuture.supplyAsync(() -> getLabelBOList(category), labelThreadPoolExecutor)).toList();
        //从completableFutureList中取出map,并将label赋值给category
        completableFutureList.forEach(future -> {
            try {
                Map<Long, List<SubjectLabelBO>> labelMap = future.get();
                categoryBOList.forEach(category -> category.setSubjectLabelBOList(labelMap.get(category.getId())));
            } catch (Exception e) {
                log.error("label赋值失败:{}", e.getMessage(), e);
            }
        });
        return categoryBOList;
    }
}
